﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Noris.Schedule.Support.Services;
using System.Drawing;
using System.Windows.Forms;
using Noris.Schedule.Planning.ProcessData;
using Noris.Schedule.Support;
using Noris.Schedule.Support.Green;
using Noris.Schedule.Planning.DataFace;
using Noris.Schedule.Support.Data;

namespace Noris.Schedule.Planning.Services
{
    #region PŘESUNUTÍ OPERACÍ TAK, ABY ZAČÍNALY SPOLEČNĚ V ČASE NEJNIŽŠÍHO ČASU POČÁTKU
    internal class FunctionMoveLinkToMinBeginCls : FunctionMoveLinkBaseCls, IFunctionMenuItem
    {
        /// <summary>
        /// Pokud předek uzná, že tato položka menu se pro graf a element má zobrazit, zdejší třída nadefinuje data pro položku menu.
        /// </summary>
        /// <param name="args"></param>
        protected override void SetMenuItem(FunctionMenuItemSuitableArgs args)
        {
            args.MenuCaption = "Zahájit linkované operace společně";
            args.MenuToolTipText = "Zajistí, že všechny linkované operace budou zahájeny současně.\r\nČas zahájení = nejnižší čas ze všech linkovaných operací.";
            args.MenuImage = PicLibrary22.Link_22_FromFile;
            args.MenuGroup = "MOVE";
            args.MenuOrder = -221;
            args.EnabledStateDependingOnElement = true;     // Enable závisí na stavu vybraných elementů
        }
        /// <summary>
        /// Určíme, zda naše položka menu má být pro aktuální element enabled / disabled
        /// </summary>
        /// <param name="args"></param>
        /// <param name="planningData"></param>
        /// <returns></returns>
        protected override bool GetMenuEnabled(FunctionMenuItemRunArgs args, PlanningDataCls planningData)
        {
            List<DataPointerStr> elements = args.InputElements;      // Seznam všech vybraných elementů (clicked + selected)
            foreach (DataPointerStr pointer in elements)
            {
                // Pokud jakýkoli jeden task, který je majitelem elementu, je v nějaké link skupině, pak vrátím true:
                CapacityPlanWorkItemCls task = planningData.FindTaskC(pointer);
                if (task != null && task.LinkGroup != 0)
                    return true;
            }
            return false;
        }
        /// <summary>
        /// Provedeme svoji akci - zahájíme linkované operace v čase nejnižšího společného začátku
        /// </summary>
        /// <param name="args"></param>
        /// <param name="planningData"></param>
        protected override void RunAction(FunctionMenuItemRunArgs args, PlanningDataCls planningData)
        {
			// Najdu task, na který se kliklo:
			CapacityPlanWorkItemCls task = planningData.FindTaskC(args.ClickedItem);
			if (task == null)
				Throw.InputError(MessageInfo.Get("Vybraný kapacitní úkol (%0) nebyl nalezen.", args.ClickedItem.Element.ToString()));
			if (task.LinkGroup == 0)
				Throw.InputError(MessageInfo.Get("Vybraný kapacitní úkol (%0) není zařazen v žádné linkované skupině operací.", args.ClickedItem.Element.ToString()));

			// Z něj najdu Group a pro ni najdu celou skupinu tasků.
			DateTime? begin = null;
			List<CapacityPlanWorkItemCls> taskList = planningData.FindTaskCLinkedList(task.LinkGroup);
			foreach (CapacityPlanWorkItemCls taskOne in taskList)
			{
				TimeRange taskTime = taskOne.TimeWork;
				if (taskTime.Begin > DateTime.MinValue && (!begin.HasValue || begin.Value > taskTime.Begin))
					begin = taskTime.Begin;
			}

			this.MoveLinkedTask(args, planningData, task.LinkGroup, new TimeVector(begin.Value, TimeRange.TimeDirection.ToFuture));
        }
    }
    #endregion
    #region PŘESUNUTÍ OPERACÍ TAK, ABY ZAČÍNALY SPOLEČNĚ V ČASE POČÁTKU KLIKNUTÉ OPERACE
    internal class FunctionMoveLinkToThisBeginCls : FunctionMoveLinkBaseCls, IFunctionMenuItem
    {
        /// <summary>
        /// Pokud předek uzná, že tato položka menu se pro graf a element má zobrazit, zdejší třída nadefinuje data pro položku menu.
        /// </summary>
        /// <param name="args"></param>
        protected override void SetMenuItem(FunctionMenuItemSuitableArgs args)
        {
            args.MenuCaption = "Zahájit linkované operace v čase této operace";
            args.MenuToolTipText = "Zajistí, že všechny linkované operace budou zahájeny současně.\r\nČas zahájení = čas zahájení vybrané operace.";
            args.MenuImage = PicLibrary22.Link_22_FromFile;
            args.MenuGroup = "MOVE";
            args.MenuOrder = -222;
            args.EnabledStateDependingOnElement = true;     // Enable závisí na stavu vybraných elementů
        }
        /// <summary>
        /// Určíme, zda naše položka menu má být pro aktuální element enabled / disabled
        /// </summary>
        /// <param name="args"></param>
        /// <param name="planningData"></param>
        /// <returns></returns>
        protected override bool GetMenuEnabled(FunctionMenuItemRunArgs args, PlanningDataCls planningData)
        {
            // Pokud task, na který se kliklo, je členem nějaké skupiny, pak vrátím true:
            CapacityPlanWorkItemCls task = planningData.FindTaskC(args.ClickedItem);
            if (task != null && task.LinkGroup != 0)
                return true;
            return false;
        }
        /// <summary>
        /// Provedeme svoji akci- zahájíme linkované operace v čase začátku aktivní operace
        /// </summary>
        /// <param name="args"></param>
        /// <param name="planningData"></param>
        protected override void RunAction(FunctionMenuItemRunArgs args, PlanningDataCls planningData)
        {
            // Určím čas počátku tasku, na který se kliklo, a s tímto časem zavolám metodu, která :
            CapacityPlanWorkItemCls task = planningData.FindTaskC(args.ClickedItem);
            if (task != null && task.LinkGroup != 0)
            {
                DateTime begin = task.TimeWork.Begin;
                this.MoveLinkedTask(args, planningData, task.LinkGroup, new TimeVector(begin, TimeRange.TimeDirection.ToFuture));
            }
        }
    }
    #endregion
    #region PŘESOUVÁNÍ LINKOVANÝCH OPERACÍ - BASE CLASS
    internal abstract class FunctionMoveLinkBaseCls : IFunctionMenuItem
    {
        #region IMPLEMENTACE INTERFACE IFunctionMenuItem A PŘEDPIS ABSTRAKTNÍCH METOD PRO POTOMKY = ŘEŠENÍ INTERAKCÍ V MENU
        /// <summary>
        /// Tady funkce deklaruje, pro které případy chce být vidět v nabídce.
        /// A pokud ano, tak jak se jmenuje, kde v nabídce je a jaký má obrázek.
        /// </summary>
        /// <param name="args"></param>
        /// <returns></returns>
        bool IFunctionMenuItem.IsFunctionSuitableFor(FunctionMenuItemSuitableArgs args)
        {
            // Link lze zadávat jen v grafu TaskCapacityLink pro elementy GraphElement třídy .Constants.ClassNumberWork:
            bool isSuitable1 = (
                args.KeyGraphMode == RowGraphMode.TaskCapacityLink &&
                args.KeyAreaType == FunctionMenuItemAreaType.GraphElement &&
                args.KeyElementClassNumber == Noris.Schedule.Planning.ProcessData.Constants.ClassNumberWork);
            bool isSuitable = isSuitable1;
            if (isSuitable)
            {
                this.SetMenuItem(args);
            }
            return isSuitable;
        }
        /// <summary>
        /// Pokud alespoň některý element je členem linku, pak akci povolím
        /// </summary>
        /// <param name="args"></param>
        /// <returns></returns>
        bool IFunctionMenuItem.IsMenuItemEnabledFor(FunctionMenuItemRunArgs args)
        {
            PlanningDataCls planningData;
            if (!PlanningDataCls.TryGetPlanningData(args.DataSource, out planningData)) return false;

            return this.GetMenuEnabled(args, planningData);
        }
        /// <summary>
        /// Vstupní metoda do výkonné části pluginu
        /// </summary>
        /// <param name="args"></param>
        void IFunctionMenuItem.Run(FunctionMenuItemRunArgs args)
        {
            PlanningDataCls planningData;
            if (!PlanningDataCls.TryGetPlanningData(args.DataSource, out planningData)) return;

            this.RunAction(args, planningData);
        }
        /// <summary>
        /// Zde potomek naplní data pro zobrazení funkce v menu, do args
        /// </summary>
        /// <param name="args"></param>
        protected abstract void SetMenuItem(FunctionMenuItemSuitableArgs args);
        /// <summary>
        /// Zde potomek určí, zda pro aktuální element má být položka menu enabled (true) / disabled (false).
        /// </summary>
        /// <param name="args"></param>
        /// <param name="planningData"></param>
        /// <returns></returns>
        protected abstract bool GetMenuEnabled(FunctionMenuItemRunArgs args, PlanningDataCls planningData);
        /// <summary>
        /// Zde potomek provede svoji funkci.
        /// </summary>
        /// <param name="args"></param>
        /// <param name="planningData"></param>
        /// <returns></returns>
        protected abstract void RunAction(FunctionMenuItemRunArgs args, PlanningDataCls planningData);
        #endregion
        #region PODPORA PRO PŘESOUVÁNÍ TASKŮ
        /// <summary>
        /// Zajistí přesun všech tasků jedné linkované skupiny na nový čas a směr
        /// </summary>
        /// <param name="args"></param>
        /// <param name="planningData"></param>
        /// <param name="linkGroup"></param>
        /// <param name="timeVector"></param>
        protected void MoveLinkedTask(FunctionMenuItemRunArgs args, PlanningDataCls planningData, int linkGroup, TimeVector timeVector)
        {
            List<CapacityPlanWorkItemCls> taskList = planningData.FindTaskCLinkedList(linkGroup);
            // Pro tuto funkci použijeme alternativní zadání PlanningInteractiveMoveArgs: 
            //   do property MoveTaskVectorDict vepíšeme tasky a jejich časové vektory (vždy stejný), jak se mají zaregistrovat jejich kapacity:
            PlanningInteractiveMoveArgs moveArgs = this.MoveLinkedTaskGetMoveArgs();
            foreach (CapacityPlanWorkItemCls task in taskList)
            {
                if (!moveArgs.MoveTaskVectorDict.ContainsKey(task.TaskGID))
                    moveArgs.MoveTaskVectorDict.Add(task.TaskGID, timeVector);
            }
            planningData.InteractiveMove(moveArgs);
            moveArgs.ResultCopyTo(args);
        }
        /// <summary>
        /// Vrací defaultní argument pro interaktivní přeplánování tasku a celého stromu
        /// </summary>
        /// <returns></returns>
        protected PlanningInteractiveMoveArgs MoveLinkedTaskGetMoveArgs()
        {
            PlanningInteractiveMoveArgs moveArgs = new PlanningInteractiveMoveArgs();
            moveArgs.CapacityLimitForActiveTask = LimitedCType.Unlimited;
            moveArgs.CapacityLimitForActiveTree = LimitedCType.ByPUCsetting;
            moveArgs.PullAdjacentForActiveTask = true;
            moveArgs.PullAdjacentForActiveTree = true;
            return moveArgs;
        }
        #endregion
    }

    #endregion
}
